"""药品上传服务

提供药品信息上传到SaaS平台的统一服务。
"""

import logging
import time
from typing import Dict, Any, List
from core.db_manager import get_db_session
from model.his.yp1 import Yp1
from sqlmodel import select, func
from fastapi_pagination import Params
from fastapi_pagination.ext.sqlmodel import paginate as sqlmodel_paginate
from config.config_manager import get_hospital_config, get_saas_config, get_batch_config
from util.saas_util import SaasUtil, SaasException
from model.saas.his_drug_info import HisDrugInfo

logger = logging.getLogger(__name__)


class DrugUploadService:
    """药品上传服务类"""
    
    def __init__(self):
        self.hospital_config = get_hospital_config()
        self.saas_config = get_saas_config()
        self.batch_config = get_batch_config()
        self.hospital_name = self.hospital_config.get("name", "医院")
    
    def get_drug_count(self) -> int:
        """获取药品信息总数
        
        Returns:
            int: 药品信息总数
        """
        try:
            with get_db_session() as session:
                statement = select(func.count(Yp1.idm))
                count = session.execute(statement).scalar()
            
            logger.info(f"{self.hospital_name} 药品信息总数: {count}")
            return count or 0
            
        except Exception as e:
            logger.error(f"获取 {self.hospital_name} 药品信息总数失败: {e}", exc_info=True)
            return 0
    
    def convert_drugs_to_saas_format(self, drugs: List[Yp1]) -> List[Dict[str, Any]]:
        """将药品数据转换为SaaS格式
        
        Args:
            drugs: 药品信息列表
            
        Returns:
            List[Dict[str, Any]]: SaaS格式的药品信息列表
        """
        data_list = []
        
        for drug in drugs:
            try:
                # 安全转换 Decimal 为字符串，避免 Pydantic 序列化警告
                def safe_decimal_to_str(value):
                    """安全地将 Decimal 转换为字符串"""
                    if value is None:
                        return None
                    return str(value)
                
                his_drug_info = HisDrugInfo(
                    hisDrugId=drug.idm,
                    hisDrugName=drug.ypmc,
                    hisDrugSpec=drug.ypgg,
                    hisPac=safe_decimal_to_str(drug.ykxs) or "1",
                    hisPacUnit=drug.jhdw,
                    hisDosUnit=drug.zxdw,
                    hisConRatio=safe_decimal_to_str(drug.ykxs),
                    hisDrugManufacturerCode=drug.cjdm,
                    hisDrugManufacturerName=drug.cjmc,
                    hisPurchaseUnit=drug.jhdw,
                    hisPurchasePrice=safe_decimal_to_str(drug.ypfj),
                    hisDoseForm=None,
                    hisApprovalNum=drug.pzwh,
                    hisDrugCountryCode=None,
                )
                # 使用 Pydantic 的 model_dump 序列化，同时排除值为None的字段
                data_list.append(his_drug_info.model_dump(by_alias=True, exclude_none=True))
                
            except Exception as e:
                logger.error(f"转换药品数据失败 (ID: {drug.idm}): {e}")
                continue
        
        return data_list
    
    def upload_drugs_in_batches(self) -> Dict[str, Any]:
        """分批上传药品信息到SaaS平台
        
        流程：
        1. 分页查询200条数据
        2. 将这200条数据作为一个批次上传到SaaS
        3. 查询下一批200条数据
        4. 继续上传下一批
        5. 循环直到所有数据处理完成
        
        Returns:
            Dict[str, Any]: 上传结果统计
        """
        batch_size = self.batch_config.get("upload_batch_size", 200)
        
        logger.info(f"开始分批上传 {self.hospital_name} 药品信息到 SaaS 平台 (每批 {batch_size} 条)")
        
        # 1. 获取SaaS配置和token
        user_account = self.saas_config.get("user_account")
        user_password = self.saas_config.get("user_password")

        if not user_account or not user_password:
            raise ValueError("SaaS user_account or user_password 未在 config.yaml 中配置")

        saas_util = SaasUtil()
        token = saas_util.get_access_token(user_account, user_password)
        if not token:
            raise Exception("获取SaaS平台token失败")
        
        # 2. 分批处理逻辑
        total_uploaded = 0
        total_failed = 0
        upload_results = []
        batch_count = 0
        page = 1
        
        try:
            while True:
                batch_count += 1
                logger.info(f"开始处理第 {batch_count} 批数据 (第 {page} 页)")
                
                # 2.1 分页查询200条数据
                with get_db_session() as session:
                    statement = select(Yp1).order_by(Yp1.ypmc)
                    result = sqlmodel_paginate(session, statement, Params(page=page, size=batch_size))
                    drugs = result.items
                
                if not drugs:
                    logger.info(f"查询完成，没有更多数据")
                    break
                
                logger.info(f"查询到第 {page} 页数据，共 {len(drugs)} 条")
                
                # 2.2 数据模型转换
                data_list = self.convert_drugs_to_saas_format(drugs)
                
                if not data_list:
                    logger.warning(f"第 {batch_count} 批数据转换后为空，跳过上传")
                    page += 1
                    continue
                
                # 2.3 上传这200条数据到SaaS
                request_data = {"dataList": data_list}
                result = saas_util.upload_his_drug_info(token, request_data)
                
                if result:
                    total_uploaded += len(data_list)
                    upload_results.append({
                        "batch": batch_count,
                        "page": page,
                        "count": len(data_list),
                        "success": True,
                        "timestamp": time.time()
                    })
                    logger.info(f"第 {batch_count} 批数据上传成功，本批 {len(data_list)} 条，累计 {total_uploaded} 条")
                else:
                    total_failed += len(data_list)
                    upload_results.append({
                        "batch": batch_count,
                        "page": page,
                        "count": len(data_list),
                        "success": False,
                        "timestamp": time.time()
                    })
                    logger.error(f"第 {batch_count} 批数据上传失败")
                
                # 2.4 如果返回的数据少于批次大小，说明已经是最后一批
                if len(drugs) < batch_size:
                    logger.info(f"查询完成，已处理所有数据")
                    break
                
                # 2.5 准备查询下一批
                page += 1
                
                # 批次间延迟，避免请求过于频繁
                time.sleep(0.5)
            
            # 3. 统计结果
            success_batches = sum(1 for r in upload_results if r["success"])
            failed_batches = len(upload_results) - success_batches
            
            result_summary = {
                "total_batches": batch_count,
                "success_batches": success_batches,
                "failed_batches": failed_batches,
                "total_uploaded": total_uploaded,
                "total_failed": total_failed,
                "upload_results": upload_results
            }
            
            logger.info(f"分批上传完成: 总共 {batch_count} 批，成功 {success_batches} 批，失败 {failed_batches} 批")
            logger.info(f"数据统计: 成功上传 {total_uploaded} 条，失败 {total_failed} 条")
            
            return result_summary
            
        except SaasException as e:
            logger.error(f"药品信息上传任务SaaS请求失败: {e}", exc_info=True)
            raise
        except Exception as e:
            logger.error(f"药品信息上传任务执行失败: {e}", exc_info=True)
            raise


# 创建全局实例
drug_upload_service = DrugUploadService()

__all__ = ["DrugUploadService", "drug_upload_service"]
